﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NFit.Core.Errors;

namespace NFit.Core.BaseClasses
{
    /// <summary>
    /// Base class for runnable element
    /// </summary>
    public abstract class RunnableElement
    {
        private Status _status;

        /// <summary>
        /// Represent the execution status of the element. If spec was not run, Status.Success is null
        /// </summary>
        public Status Status
        {
            get
            {
                if (_status == null)
                    _status = new Status();
                return _status;
            }
        }

        private string _id = Guid.NewGuid().ToString();

        /// <summary>
        /// Id of the element. The Id is initialized with a Guid
        /// </summary>
        public string Id
        {
            get
            {
                return _id;
            }
            set
            {
                _id = value;
            }
        }

        private string _name;

        /// <summary>
        /// The name of the element
        /// </summary>
        public string Name
        {
            get
            {
                if (string.IsNullOrEmpty(_name))
                    return Id;

                return _name;
            }
            set
            {
                _name = value;
            }
        }

        /// <summary>
        /// Indicate if the element has a name
        /// </summary>
        public bool HasName
        {
            get
            {
                return !string.IsNullOrEmpty(_name);
            }
        }

        /// <summary>
        /// Indicate if the test is successful. Note that it returns false if the test was not run
        /// </summary>
        public bool IsSuccessful
        {
            get
            {
                return Status.IsSuccessful;
            }
        }

        /// <summary>
        /// Indicate if the cell has one or more errors
        /// </summary>
        public bool HasErrors
        {
            get
            {
                return Status.NestedError != null;
            }
        }

        /// <summary>
        /// Indicate if the element has an error of the provided type
        /// </summary>
        /// <typeparam name="T">The type of the error to match</typeparam>
        /// <returns>true if the element as a corresponding error</returns>
        public virtual bool HasError<T>() where T : NFitError
        {
            return HasError<T>(null);
        }

        /// <summary>
        /// Indicate if the element has an error of the provided type and that match a predicate
        /// </summary>
        /// <typeparam name="T">The type of the error to match</typeparam>
        /// <param name="checkError">A predicate used to check error's properties</param>
        /// <returns>true if the element as a corresponding error</returns>
        public virtual bool HasError<T>(Predicate<T> checkError) where T : NFitError
        {
            if (Status.HasError<T>(checkError))
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// The source of the element
        /// </summary>
        public object Source { get; set; }
    }
}
